%{
#include "stdio.h"
#include "symbol_table.h"

int getLineNumber(void);

%}

/* tokens for var types (leaf nodes)  */
%token KW_INT
%token KW_BYTE

/* tokens for control flow */
%token KW_IF
%token KW_THEN
%token KW_ELSE
%token KW_WHILE

/* tokens for commands */
%token KW_PRINT
%token KW_RETURN
%token KW_READ

/* tokens for operators */
%token OPERATOR_L
%token OPERATOR_G
%token OPERATOR_LE
%token OPERATOR_GE
%token OPERATOR_EQ
%token OPERATOR_NE
%token OPERATOR_AND
%token OPERATOR_OR

/* token for identifier */
%token <symbol> TK_IDENTIFIER

/* tokens for literals */
%token LIT_CHAR
%token LIT_INTEGER
%token LIT_STRING

%token TOKEN_ERROR   290

/* Intermediate nodes */

%nonassoc '!'
%left OPERATOR_AND OPERATOR_OR
%left OPERATOR_LE OPERATOR_GE OPERATOR_EQ OPERATOR_NE
%left '+' '-'
%left '*' '/'

%union {
    table_entry_node* symbol;
}

%start program

%%

/* Production rule for the program */
program: declarations
    ;

declarations: declaration
    | declarations declaration
    ;

declaration: type TK_IDENTIFIER ';'
    | type TK_IDENTIFIER '[' LIT_INTEGER ']' ';'
    | type TK_IDENTIFIER '(' param_list ')' cmd_block
    ;

param: type TK_IDENTIFIER
	;

param_list: param parrest
	|
	;

parrest: param parrest
        |
        ;

/* Production rule for variable types */
type: KW_INT
	| KW_BYTE
	;

cmd_list: cmd cmd_rest
        ;

cmd_rest: ';' cmd_list
        |
        ;

cmd: TK_IDENTIFIER '=' expr
    | TK_IDENTIFIER '[' expr ']' '=' expr
    | KW_IF '(' expr ')' KW_THEN cmd
    | KW_IF '(' expr ')' KW_THEN cmd KW_ELSE cmd
    | KW_WHILE '(' expr ')' cmd
    | cmd_block
    | KW_PRINT expr
    | KW_PRINT LIT_STRING
    | KW_RETURN expr
    | KW_READ TK_IDENTIFIER
    |
;

cmd_block: '{' cmd_list '}'
    ;

expr: expr '+' expr
    | expr '-' expr
    | expr '*' expr
    | expr '/' expr
    | '-' expr
    | '(' expr ')'
    | TK_IDENTIFIER
    | LIT_INTEGER
    | LIT_CHAR
    | '!' expr
    | expr OPERATOR_OR expr
    | expr OPERATOR_AND expr
    | expr OPERATOR_LE expr
    | expr OPERATOR_G expr
    | expr OPERATOR_L expr
    | expr OPERATOR_GE expr
    | expr OPERATOR_EQ expr
    | expr OPERATOR_NE expr
    ;

%%

int yyerror(char *s) {
    fprintf(stderr, "%s on line: %d\n", s, getLineNumber());

	// end the program with an error code.
	exit(3);
}
